package com.kexio.auth.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.kexio.auth.annotation.RateLimit;
import com.kexio.auth.service.RateLimitService;
import com.kexio.common.exception.BusinessException;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 限流切面
 * 
 * 拦截标注了@RateLimit注解的方法，执行限流检查。
 * 支持多种限流算法和策略，基于Redis实现分布式限流。
 * 
 * 功能特性：
 * - 滑动窗口算法（精确控制）
 * - 令牌桶算法（支持突发流量）
 * - 固定窗口算法（简单高效）
 * - 多维度限流（用户、IP、全局、自定义）
 * - 多租户支持
 * - 优雅降级（Redis异常时不影响业务）
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Aspect
@Order(5) // 限流检查最优先，在所有其他业务逻辑之前
public class RateLimitAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
    
    @Autowired
    private RateLimitService rateLimitService;
    
    /**
     * 拦截@RateLimit注解的方法
     * 执行限流检查
     */
    @Around("@annotation(rateLimit)")
    public Object handleRateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodSignature = signature.getDeclaringTypeName() + "." + method.getName();
        
        logger.debug("🚦 开始限流检查: {} - 限制: {}次/{}{} - 算法: {}", 
            methodSignature, rateLimit.count(), rateLimit.time(), 
            rateLimit.timeUnit().toString().toLowerCase(), rateLimit.algorithm());
        
        try {
            // 1. 获取HTTP请求对象
            HttpServletRequest request = getCurrentHttpRequest();
            
            // 2. 执行限流检查
            boolean isLimited = rateLimitService.isRateLimited(rateLimit, request, methodSignature);
            
            if (isLimited) {
                // 3. 被限流，抛出异常
                String message = rateLimit.message().isEmpty() 
                    ? String.format("访问过于频繁，请稍后再试。限制: %d次/%d%s", 
                        rateLimit.count(), rateLimit.time(), 
                        rateLimit.timeUnit().toString().toLowerCase())
                    : rateLimit.message();
                
                logger.warn("🚫 请求被限流: {} - {}", methodSignature, message);
                throw new BusinessException(message);
            }
            
            // 4. 未被限流，执行目标方法
            logger.debug("✅ 限流检查通过: {}", methodSignature);
            return joinPoint.proceed();
            
        } catch (BusinessException e) {
            // 业务异常直接抛出（限流异常）
            throw e;
        } catch (Exception e) {
            // 其他异常记录日志但不影响业务
            logger.error("🔥 限流检查过程中发生异常: {} - {}", methodSignature, e.getMessage(), e);
            
            // 异常时不限流，优雅降级
            logger.warn("⚠️ 限流检查异常，允许请求通过: {}", methodSignature);
            return joinPoint.proceed();
        }
    }
    
    /**
     * 获取当前HTTP请求对象
     */
    private HttpServletRequest getCurrentHttpRequest() {
        try {
            ServletRequestAttributes attributes = 
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getRequest() : null;
        } catch (Exception e) {
            logger.warn("无法获取HTTP请求对象: {}", e.getMessage());
            return null;
        }
    }
}
